﻿#define MyAppName       "Miranda IM for Windows Search"
#define MyAppURL        "https://code.google.com/p/mirandasearch/"
#define MyAppExe        "MirandaSearch-32.dll"
#define MyAppSource	    "..\Win32\Release\" + MyAppExe
#define MyAppId			    GetStringFileInfo( MyAppSource, INTERNAL_NAME )
#define MyAppVersion    GetFileProductVersion( MyAppSource )
#define MyAppCopyright	GetFileCopyright( MyAppSource )
#define MyAppPublisher	GetFileCompany( MyAppSource )
#define MyOutput        "..\..\..\redist\mirandasearch-" + MyAppVersion

#define APPID           "{{478232E9-A7BD-4FD6-AAB4-D6A54651AAF9}}"
#define CLSID	          "{{1E5FCA4F-79CB-423B-A6CE-678DD6F574C8}}"

; Packing sources
#expr Exec( "cmd.exe", "/c .\setup\Pack.cmd " + MyAppVersion, ".." )

[Setup]
AppId={#MyAppId}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
VersionInfoVersion={#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
AppCopyright={#MyAppCopyright}
UsePreviousAppDir=no
DefaultDirName={code:GetMirandaIMFolder|Plugins}
OutputDir=Release
OutputBaseFilename={#MyOutput}
Compression=lzma2/ultra64
SolidCompression=yes
InternalCompressLevel=ultra64
LZMAUseSeparateProcess=yes
PrivilegesRequired=admin
ChangesAssociations=yes
UninstallDisplayIcon={app}\{#MyAppExe},1
UninstallFilesDir={app}\MirandaSearch Data
DirExistsWarning=no
WizardImageFile=compiler:WizModernImage-IS.bmp
WizardSmallImageFile=compiler:WizModernSmallImage-IS.bmp
SetupIconFile=Setup.ico
OutputManifestFile=Setup-Manifest.txt

[Files]
Source: "..\Win32\Release\MirandaSearch-32.dll";	DestDir: "{app}"; Flags: replacesameversion uninsrestartdelete restartreplace regserver 32bit
Source: "..\x64\Release\MirandaSearch-64.dll";		DestDir: "{app}"; Flags: replacesameversion uninsrestartdelete restartreplace regserver 64bit; Check: IsWin64()
Source: "..\ReadMe.txt";							DestDir: "{app}\MirandaSearch Data"; Flags: replacesameversion uninsrestartdelete restartreplace
Source: "..\Translation.txt";						DestDir: "{app}\MirandaSearch Data"; Flags: replacesameversion uninsrestartdelete restartreplace
Source: "..\SetupMSI\bin\32\mspr.msi";				DestDir: "{app}\MirandaSearch Data"; Flags: replacesameversion uninsrestartdelete restartreplace 32bit; Check: not IsWin64()
Source: "..\SetupMSI\bin\64\mspr.msi";				DestDir: "{app}\MirandaSearch Data"; Flags: replacesameversion uninsrestartdelete restartreplace 64bit; Check: IsWin64()

[UninstallDelete]
Name: "{app}\MirandaSearch-64.dll";	Type: files
Name: "{app}\MirandaSearch-32.dll";	Type: files
Name: "{app}\MirandaSearch Data";	Type: dirifempty
Name: "{app}";						Type: dirifempty

[Run]
Filename: "msiexec.exe"; Parameters: "/i ""{app}\MirandaSearch Data\mspr.msi"" /q"; WorkingDir: "{app}\MirandaSearch Data"; StatusMsg: "Registering Windows Search..."; Check: FileExists(ExpandConstant('{app}\MirandaSearch Data\mspr.msi'))

[UninstallRun]
Filename: "msiexec.exe"; Parameters: "/x ""{app}\MirandaSearch Data\mspr.msi"" /q"; WorkingDir: "{app}\MirandaSearch Data"; StatusMsg: "Unregistering Windows Search..."; Check: FileExists(ExpandConstant('{app}\MirandaSearch Data\mspr.msi'))

[Registry]
; Fixed interface names
Root: HKCR; Subkey: "Interface\{{C731065D-AC80-11D1-8DF3-00C04FB6EF4F}}";										ValueType: string; ValueName: "";				ValueData: "IOpLockStatus"; Flags: createvalueifdoesntexist noerror
Root: HKCR; Subkey: "Interface\{{C73106E1-AC80-11D1-8DF3-00C04FB6EF4F}}";										ValueType: string; ValueName: "";				ValueData: "ISearchProtocolThreadContext"; Flags: createvalueifdoesntexist noerror
Root: HKCR; Subkey: "Interface\{{89BCB740-6119-101A-BCB7-00DD010655AF}}";										ValueType: string; ValueName: "";				ValueData: "IFilter"; Flags: createvalueifdoesntexist noerror
Root: HKCR; Subkey: "Interface\{{0B63E318-9CCC-11D0-BCDB-00805FCCCE04}}";										ValueType: string; ValueName: "";				ValueData: "IUrlAccessor"; Flags: createvalueifdoesntexist noerror
Root: HKCR; Subkey: "Interface\{{C7310734-AC80-11D1-8DF3-00C04FB6EF4F}}";										ValueType: string; ValueName: "";				ValueData: "IUrlAccessor2"; Flags: createvalueifdoesntexist noerror
Root: HKCR; Subkey: "Interface\{{6FBC7005-0455-4874-B8FF-7439450241A3}}";										ValueType: string; ValueName: "";				ValueData: "IUrlAccessor3"; Flags: createvalueifdoesntexist noerror
Root: HKCR; Subkey: "Interface\{{5CC51041-C8D2-41d7-BCA3-9E9E286297DC}}";										ValueType: string; ValueName: "";				ValueData: "IUrlAccessor4"; Flags: createvalueifdoesntexist noerror
Root: HKCR; Subkey: "Interface\{{C73106BA-AC80-11D1-8DF3-00C04FB6EF4F}}";										ValueType: string; ValueName: "";				ValueData: "ISearchProtocol"; Flags: createvalueifdoesntexist noerror
Root: HKCR; Subkey: "Interface\{{7789F0B2-B5B2-4722-8B65-5DBD150697A9}}";										ValueType: string; ValueName: "";				ValueData: "ISearchProtocol2"; Flags: createvalueifdoesntexist noerror
Root: HKCR; Subkey: "Interface\{{0B63E385-9CCC-11D0-BCDB-00805FCCCE04}}";										ValueType: string; ValueName: "";				ValueData: "IProtocolHandlerSite"; Flags: createvalueifdoesntexist noerror
Root: HKCR; Subkey: "Interface\{{01E18D10-4D8B-11d2-855D-006008059367}}";										ValueType: string; ValueName: "";				ValueData: "IFileSystemBindData"; Flags: createvalueifdoesntexist noerror
Root: HKCR; Subkey: "Interface\{{79EAC9EC-BAF9-11CE-8C82-00AA004BA90B}}";										ValueType: string; ValueName: "";				ValueData: "IInternetProtocolInfo"; Flags: createvalueifdoesntexist noerror
Root: HKCR; Subkey: "Interface\{{79EAC9E3-BAF9-11CE-8C82-00AA004BA90B}}";										ValueType: string; ValueName: "";				ValueData: "IInternetProtocolRoot"; Flags: createvalueifdoesntexist noerror
Root: HKCR; Subkey: "Interface\{{79EAC9E4-BAF9-11CE-8C82-00AA004BA90B}}";										ValueType: string; ValueName: "";				ValueData: "IInternetProtocol"; Flags: createvalueifdoesntexist noerror
Root: HKCR; Subkey: "Interface\{{C7A98E66-1010-492c-A1C8-C809E1F75905}}";										ValueType: string; ValueName: "";				ValueData: "IInternetProtocolEx"; Flags: createvalueifdoesntexist noerror
Root: HKCR; Subkey: "Interface\{{ADD8BA80-002B-11D0-8F0F-00C04FD7D062}}";										ValueType: string; ValueName: "";				ValueData: "IDelegateFolder"; Flags: createvalueifdoesntexist noerror
Root: HKCR; Subkey: "Interface\{{79EAC9EB-BAF9-11CE-8C82-00AA004BA90B}}";										ValueType: string; ValueName: "";				ValueData: "IInternetPriority"; Flags: createvalueifdoesntexist noerror
Root: HKCR; Subkey: "Interface\{{DD1EC3B3-8391-4fdb-A9E6-347C3CAAA7DD}}";										ValueType: string; ValueName: "";				ValueData: "IWinInetCacheHints"; Flags: createvalueifdoesntexist noerror
Root: HKCR; Subkey: "Interface\{{79EAC9E3-BAF9-11CE-8C82-00AA004BA90B}}";										ValueType: string; ValueName: "";				ValueData: "IInternetProtocolRoot"; Flags: createvalueifdoesntexist noerror
Root: HKCR; Subkey: "Interface\{{79EAC9E4-BAF9-11CE-8C82-00AA004BA90B}}";										ValueType: string; ValueName: "";				ValueData: "IInternetProtocol"; Flags: createvalueifdoesntexist noerror
Root: HKCR; Subkey: "Interface\{{79EAC9EC-BAF9-11CE-8C82-00AA004BA90B}}";										ValueType: string; ValueName: "";				ValueData: "IInternetProtocolInfo"; Flags: createvalueifdoesntexist noerror

; Clean-up
Root: HKCR; Subkey: "miranda";																					ValueType:   none; Flags: dontcreatekey uninsdeletekey noerror
Root: HKCR; Subkey: "MirandaSearch.MirandaProtocol";															ValueType:   none; Flags: dontcreatekey uninsdeletekey noerror
Root: HKCR; Subkey: "MirandaSearch.MirandaProtocol.1";															ValueType:   none; Flags: dontcreatekey uninsdeletekey noerror
Root: HKCR; Subkey: "CLSID\{#CLSID}";																			ValueType:   none; Flags: dontcreatekey uninsdeletekey noerror
Root: HKCR; Subkey: "MirandaSearch.MirandaFilter";																ValueType:   none; Flags: dontcreatekey uninsdeletekey noerror
Root: HKCR; Subkey: "MirandaSearch.MirandaFilter.1";															ValueType:   none; Flags: dontcreatekey uninsdeletekey noerror
Root: HKCR; Subkey: "CLSID\{{65E4D50B-CF07-4A10-9F81-B91FD5B68674}}";											ValueType:   none; Flags: dontcreatekey uninsdeletekey noerror
Root: HKCR; Subkey: "MirandaSearch.MirandaAccessor";															ValueType:   none; Flags: dontcreatekey uninsdeletekey noerror
Root: HKCR; Subkey: "MirandaSearch.MirandaAccessor.1";															ValueType:   none; Flags: dontcreatekey uninsdeletekey noerror
Root: HKCR; Subkey: "CLSID\{{9883EC9C-FBF2-431E-B3A4-15700A9422FD}}";											ValueType:   none; Flags: dontcreatekey uninsdeletekey noerror
Root: HKCR; Subkey: "AppID\{#APPID}";																			ValueType:   none; Flags: dontcreatekey uninsdeletekey noerror
Root: HKCR; Subkey: "AppID\MirandaSearch-32.dll";																ValueType:   none; Flags: dontcreatekey uninsdeletekey noerror
Root: HKCR; Subkey: "AppID\MirandaSearch-64.dll";																ValueType:   none; Flags: dontcreatekey uninsdeletekey noerror
Root: HKCR; Subkey: "TypeLib\{{8181DA9E-3DBB-40BA-998D-30B471A1D363}}";											ValueType:   none; Flags: dontcreatekey uninsdeletekey noerror

; 32-bit
Root: HKCU32; Subkey: "Software\Microsoft\Windows\Shell\Associations\UrlAssociations\miranda\UserChoice";		ValueType: string; ValueName: "Progid";			ValueData: "IE.HTTP"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror
Root: HKCU32; Subkey: "Software\Microsoft\Windows\Shell\Associations\UrlAssociations\miranda";					ValueType:   none; Flags: dontcreatekey uninsdeletekey noerror

Root: HKCU32; Subkey: "Software\Microsoft\Windows\CurrentVersion\Internet Settings\PluggableProtocols";			ValueType: string; ValueName: "miranda";		ValueData: ""; Flags: uninsdeletekeyifempty uninsdeletevalue noerror
Root: HKCU32; Subkey: "Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\ProtocolDefaults";	ValueType:  dword; ValueName: "miranda";		ValueData: "0"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror

Root: HKLM32; Subkey: "Software\Microsoft\Windows\Shell\Associations\UrlAssociations\miranda\UserChoice";		ValueType: string; ValueName: "Progid";			ValueData: "IE.HTTP"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror
Root: HKLM32; Subkey: "Software\Microsoft\Windows\Shell\Associations\UrlAssociations\miranda";					ValueType:   none; Flags: dontcreatekey uninsdeletekey noerror

Root: HKLM32; Subkey: "Software\Microsoft\Internet Explorer\Capabilities\UrlAssociations";						ValueType: string; ValueName: "miranda";		ValueData: "IE.HTTP"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror
Root: HKLM32; Subkey: "Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved";					ValueType: string; ValueName: "{#CLSID}";		ValueData: "{#MyAppName}"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror
Root: HKLM32; Subkey: "Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\ProtocolDefaults";	ValueType:  dword; ValueName: "miranda";		ValueData: "0"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror

Root: HKLM32; Subkey: "Software\Microsoft\Windows Search\Gather\Windows\SystemIndex\Protocols\miranda\0";		ValueType:  dword; ValueName: "Included";		ValueData: "1"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror
Root: HKLM32; Subkey: "Software\Microsoft\Windows Search\Gather\Windows\SystemIndex\Protocols\miranda\0";		ValueType: string; ValueName: "ProgIdHandler";	ValueData: "MirandaSearch.MirandaProtocol.1"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror
Root: HKLM32; Subkey: "Software\Microsoft\Windows Search\Gather\Windows\SystemIndex\Protocols\miranda";			ValueType:   none; Flags: dontcreatekey uninsdeletekey noerror

Root: HKLM32; Subkey: "Software\Microsoft\Windows Search\ProtocolHandlers";										ValueType: string; ValueName: "miranda";		ValueData: "MirandaSearch.MirandaProtocol.1"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror

Root: HKLM32; Subkey: "Software\Microsoft\Windows Search\PHSearchConnectors\miranda\Default";					ValueType: string; ValueName: "Name";			ValueData: "Miranda IM"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror
Root: HKLM32; Subkey: "Software\Microsoft\Windows Search\PHSearchConnectors\miranda\Default";					ValueType: string; ValueName: "Description";	ValueData: "Miranda IM messages"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror
Root: HKLM32; Subkey: "Software\Microsoft\Windows Search\PHSearchConnectors\miranda\Default";					ValueType: string; ValueName: "FolderType";		ValueData: "{{91475fe5-586b-4eba-8d75-d17434b8cdf6}}"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror
Root: HKLM32; Subkey: "Software\Microsoft\Windows Search\PHSearchConnectors\miranda";							ValueType:   none; Flags: dontcreatekey uninsdeletekey noerror

Root: HKLM32; Subkey: "Software\Classes\PROTOCOLS\Handler\miranda";												ValueType: string; ValueName: "";				ValueData: "Miranda IM protocol for Windows Search"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror
Root: HKLM32; Subkey: "Software\Classes\PROTOCOLS\Handler\miranda";												ValueType: string; ValueName: "CLSID";			ValueData: "{#CLSID}"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror
Root: HKLM32; Subkey: "Software\Classes\PROTOCOLS\Handler\miranda";												ValueType:   none; Flags: dontcreatekey uninsdeletekey noerror

; 64-bit
Root: HKCU64; Subkey: "Software\Microsoft\Windows\Shell\Associations\UrlAssociations\miranda\UserChoice";		ValueType: string; ValueName: "Progid";			ValueData: "IE.HTTP"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror; Check: IsWin64()
Root: HKCU64; Subkey: "Software\Microsoft\Windows\Shell\Associations\UrlAssociations\miranda";					ValueType:   none; Flags: dontcreatekey uninsdeletekey noerror; Check: IsWin64()

Root: HKCU64; Subkey: "Software\Microsoft\Windows\CurrentVersion\Internet Settings\PluggableProtocols";			ValueType: string; ValueName: "miranda";		ValueData: ""; Flags: uninsdeletekeyifempty uninsdeletevalue noerror; Check: IsWin64()
Root: HKCU64; Subkey: "Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\ProtocolDefaults";	ValueType:  dword; ValueName: "miranda";		ValueData: "0"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror; Check: IsWin64()

Root: HKLM64; Subkey: "Software\Microsoft\Windows\Shell\Associations\UrlAssociations\miranda\UserChoice";		ValueType: string; ValueName: "Progid";			ValueData: "IE.HTTP"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror; Check: IsWin64()
Root: HKLM64; Subkey: "Software\Microsoft\Windows\Shell\Associations\UrlAssociations\miranda";					ValueType:   none; Flags: dontcreatekey uninsdeletekey noerror; Check: IsWin64()

Root: HKLM64; Subkey: "Software\Microsoft\Internet Explorer\Capabilities\UrlAssociations";						ValueType: string; ValueName: "miranda";		ValueData: "IE.HTTP"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror; Check: IsWin64()
Root: HKLM64; Subkey: "Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved";					ValueType: string; ValueName: "{#CLSID}";		ValueData: "{#MyAppName}"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror; Check: IsWin64()
Root: HKLM64; Subkey: "Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\ProtocolDefaults";	ValueType:  dword; ValueName: "miranda";		ValueData: "0"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror; Check: IsWin64()

Root: HKLM64; Subkey: "Software\Microsoft\Windows Search\Gather\Windows\SystemIndex\Protocols\miranda\0";		ValueType:  dword; ValueName: "Included";		ValueData: "1"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror; Check: IsWin64()
Root: HKLM64; Subkey: "Software\Microsoft\Windows Search\Gather\Windows\SystemIndex\Protocols\miranda\0";		ValueType: string; ValueName: "ProgIdHandler";	ValueData: "MirandaSearch.MirandaProtocol.1"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror; Check: IsWin64()
Root: HKLM64; Subkey: "Software\Microsoft\Windows Search\Gather\Windows\SystemIndex\Protocols\miranda";			ValueType:   none; Flags: dontcreatekey uninsdeletekey noerror; Check: IsWin64()

Root: HKLM64; Subkey: "Software\Microsoft\Windows Search\ProtocolHandlers";										ValueType: string; ValueName: "miranda";		ValueData: "MirandaSearch.MirandaProtocol.1"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror; Check: IsWin64()

Root: HKLM64; Subkey: "Software\Microsoft\Windows Search\PHSearchConnectors\miranda\Default";					ValueType: string; ValueName: "Name";			ValueData: "Miranda IM"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror; Check: IsWin64()
Root: HKLM64; Subkey: "Software\Microsoft\Windows Search\PHSearchConnectors\miranda\Default";					ValueType: string; ValueName: "Description";	ValueData: "Miranda IM messages"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror; Check: IsWin64()
Root: HKLM64; Subkey: "Software\Microsoft\Windows Search\PHSearchConnectors\miranda\Default";					ValueType: string; ValueName: "FolderType";		ValueData: "{{91475fe5-586b-4eba-8d75-d17434b8cdf6}}"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror; Check: IsWin64()
Root: HKLM64; Subkey: "Software\Microsoft\Windows Search\PHSearchConnectors\miranda";							ValueType:   none; Flags: dontcreatekey uninsdeletekey noerror; Check: IsWin64()

Root: HKLM64; Subkey: "Software\Classes\PROTOCOLS\Handler\miranda";												ValueType: string; ValueName: "";				ValueData: "Miranda IM protocol for Windows Search"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror; Check: IsWin64()
Root: HKLM64; Subkey: "Software\Classes\PROTOCOLS\Handler\miranda";												ValueType: string; ValueName: "CLSID";			ValueData: "{#CLSID}"; Flags: uninsdeletekeyifempty uninsdeletevalue noerror; Check: IsWin64()
Root: HKLM64; Subkey: "Software\Classes\PROTOCOLS\Handler\miranda";												ValueType:   none; Flags: dontcreatekey uninsdeletekey noerror; Check: IsWin64()

[Code]

// Services API

type
	SERVICE_STATUS = record
    	dwServiceType				: cardinal;
    	dwCurrentState				: cardinal;
    	dwControlsAccepted			: cardinal;
    	dwWin32ExitCode				: cardinal;
    	dwServiceSpecificExitCode	: cardinal;
    	dwCheckPoint				: cardinal;
    	dwWaitHint					: cardinal;
	end;
	HANDLE = cardinal;

const
	SERVICE_QUERY_CONFIG		= $1;
	SERVICE_CHANGE_CONFIG		= $2;
	SERVICE_QUERY_STATUS		= $4;
	SERVICE_START				= $10;
	SERVICE_STOP				= $20;
	SERVICE_ALL_ACCESS			= $f01ff;
	SC_MANAGER_ALL_ACCESS		= $f003f;
	SERVICE_WIN32_OWN_PROCESS	= $10;
	SERVICE_WIN32_SHARE_PROCESS	= $20;
	SERVICE_WIN32				= $30;
	SERVICE_INTERACTIVE_PROCESS = $100;
	SERVICE_BOOT_START          = $0;
	SERVICE_SYSTEM_START        = $1;
	SERVICE_AUTO_START          = $2;
	SERVICE_DEMAND_START        = $3;
	SERVICE_DISABLED            = $4;
	SERVICE_DELETE              = $10000;
	SERVICE_CONTROL_STOP		= $1;
	SERVICE_CONTROL_PAUSE		= $2;
	SERVICE_CONTROL_CONTINUE	= $3;
	SERVICE_CONTROL_INTERROGATE = $4;
	SERVICE_STOPPED				= $1;
	SERVICE_START_PENDING       = $2;
	SERVICE_STOP_PENDING        = $3;
	SERVICE_RUNNING             = $4;
	SERVICE_CONTINUE_PENDING    = $5;
	SERVICE_PAUSE_PENDING       = $6;
	SERVICE_PAUSED              = $7;

function OpenSCManager(lpMachineName, lpDatabaseName: string; dwDesiredAccess :cardinal): HANDLE;
external 'OpenSCManagerW@advapi32.dll stdcall';

function OpenService(hSCManager :HANDLE;lpServiceName: string; dwDesiredAccess :cardinal): HANDLE;
external 'OpenServiceW@advapi32.dll stdcall';

function CloseServiceHandle(hSCObject :HANDLE): boolean;
external 'CloseServiceHandle@advapi32.dll stdcall';

function CreateService(hSCManager :HANDLE;lpServiceName, lpDisplayName: string;dwDesiredAccess,dwServiceType,dwStartType,dwErrorControl: cardinal;lpBinaryPathName,lpLoadOrderGroup: String; lpdwTagId : cardinal;lpDependencies,lpServiceStartName,lpPassword :string): cardinal;
external 'CreateServiceW@advapi32.dll stdcall';

function DeleteService(hService :HANDLE): boolean;
external 'DeleteService@advapi32.dll stdcall';

function StartNTService(hService :HANDLE;dwNumServiceArgs : cardinal;lpServiceArgVectors : cardinal) : boolean;
external 'StartServiceW@advapi32.dll stdcall';

function ControlService(hService :HANDLE; dwControl :cardinal;var ServiceStatus :SERVICE_STATUS) : boolean;
external 'ControlService@advapi32.dll stdcall';

function QueryServiceStatus(hService :HANDLE;var ServiceStatus :SERVICE_STATUS) : boolean;
external 'QueryServiceStatus@advapi32.dll stdcall';

function QueryServiceStatusEx(hService :HANDLE;ServiceStatus :SERVICE_STATUS) : boolean;
external 'QueryServiceStatus@advapi32.dll stdcall';

function StartService(ServiceName: string) : boolean;
var
	hSCM	: HANDLE;
	hService: HANDLE;
begin
	hSCM := OpenSCManager( '', 'ServicesActive', SC_MANAGER_ALL_ACCESS );
	Result := false;
	if hSCM <> 0 then begin
		hService := OpenService( hSCM, ServiceName, SERVICE_START );
        if hService <> 0 then begin
        	Result := StartNTService( hService, 0, 0 );
            CloseServiceHandle( hService );
		end;
        CloseServiceHandle(hSCM)
	end;
end;

function StopService(ServiceName: string) : boolean;
var
	hSCM	: HANDLE;
	hService: HANDLE;
	Status	: SERVICE_STATUS;
begin
	hSCM := OpenSCManager( '', 'ServicesActive', SC_MANAGER_ALL_ACCESS );
	Result := false;
	if hSCM <> 0 then begin
		hService := OpenService( hSCM, ServiceName, SERVICE_STOP );
        if hService <> 0 then begin
        	Result := ControlService( hService, SERVICE_CONTROL_STOP, Status );
            CloseServiceHandle( hService );
		end;
        CloseServiceHandle( hSCM );
	end;
end;

function IsServiceRunning(ServiceName: string) : boolean;
var
	hSCM	: HANDLE;
	hService: HANDLE;
	Status	: SERVICE_STATUS;
begin
	hSCM := OpenSCManager( '', 'ServicesActive', SC_MANAGER_ALL_ACCESS );
	Result := false;
	if hSCM <> 0 then begin
		hService := OpenService( hSCM, ServiceName, SERVICE_QUERY_STATUS );
    	if hService <> 0 then begin
			if QueryServiceStatus( hService, Status ) then begin
				Result := ( Status.dwCurrentState = SERVICE_RUNNING );
        	end;
            CloseServiceHandle(hService);
		end;
		CloseServiceHandle( hSCM );
	end;
end;

// PS API

type
	HMODULE  = HANDLE;
	pHMODULE = Array[0..255] of HMODULE;
	LPDWORD  = DWORD;
	PDWORD   = Array[0..255] of DWORD;
	LPTSTR   = String;
	PROCESSENTRY32 = record
		dwSize				: DWORD;
		cntUsage			: DWORD;
		th32ProcessID		: DWORD;
		th32DefaultHeapID	: DWORD;
		th32ModuleID		: DWORD;
		cntThreads			: DWORD;
		th32ParentProcessID	: DWORD;
		pcPriClassBase		: DWORD;
		dwFlags				: DWORD;
		szExeFile			: Array[0..259] of Char;
	end;

const
	PROCESS_QUERY_INFORMATION			= $0400;
	PROCESS_QUERY_LIMITED_INFORMATION	= $1000;
	MAX_LENGTH							= 1024;
	WM_DESTROY							= $0002;
	WM_CLOSE							= $0010;
	WM_SYSCOMMAND						= $0112;
	SC_CLOSE							= $F060;

function CreateToolhelp32Snapshot(dwFlags : DWORD; th32ProcessID : DWORD) : HANDLE;
external 'CreateToolhelp32Snapshot@kernel32.dll stdcall';

function Process32First(hSnapshot : HANDLE; var lppe : PROCESSENTRY32 ) : BOOL;
external 'Process32FirstW@kernel32.dll stdcall';

function Process32Next(hSnapshot : HANDLE; var lppe : PROCESSENTRY32 ) : BOOL;
external 'Process32NextW@kernel32.dll stdcall';

function OpenProcess(dwDesiredAccess : DWORD; bInheritHandle : Boolean; dwProcessId : DWORD) : HANDLE;
external 'OpenProcess@kernel32.dll stdcall';

function CloseHandle(hObject : HANDLE) : BOOL;
external 'CloseHandle@kernel32.dll stdcall';

function EnumProcesses(var pProcessIds : PDWORD; cb : DWORD; var pBytesReturned : DWORD) : BOOL;
external 'EnumProcesses@psapi.dll stdcall';

function GetProcessImageFileName(hProcess : HANDLE; lpFilename : LPTSTR; nSize : DWORD) : DWORD;
external 'GetProcessImageFileNameW@psapi.dll stdcall';

function QueryDosDevice(lpDeviceName : LPTSTR; lpTargetPath : LPTSTR; ucchMax : DWORD) : DWORD;
external 'QueryDosDeviceW@kernel32.dll stdcall';

// Convert device name to file name i.e. '\Device\HarddiskVolume2\Windows' to 'C:\Windows' (empty string on errors)
function GetFilenameFromDevicename(FilenameAsDevice : String) : String;
var
	disk		: Byte;
	diskname	: String;
	device		: LPTSTR;
	devicename	: String;
	length		: Integer;
begin
	Result := '';
	disk := Ord( 'A' );
	while ( ( Result = '' ) and ( disk <= Ord( 'Z' ) ) ) do begin
		diskname := StringOfChar( Chr( disk ), 1 ) + ':';
		device := '';
		SetLength( device, MAX_LENGTH );
		if ( QueryDosDevice( diskname, device, MAX_LENGTH ) > 0 ) then begin
			length := Pos( #0, device ) - 1;
			devicename := Copy( device, 1, length );
			if ( LowerCase( Copy( FilenameAsDevice, 1, length ) ) = LowerCase( devicename ) ) then begin
				Delete( FilenameAsDevice, 1, length );
				Result := diskname + FilenameAsDevice;
			end;
		end;
		disk := disk + 1;
	end;
end;

// Get full path name of running process (empty string otherwise)
function GetRunning(procName : String) : String;
var
	found       : Boolean;
	length		: Integer;
	filename    : String;
	entry       : DWORD;
	maxEntries  : DWORD;
	processes   : PDWORD;
	lpFilename  : LPTSTR;
	hProcess    : HANDLE;
begin
	Result := '';
	found := False;
	if ( EnumProcesses( processes, SizeOf( processes ), maxEntries ) ) then begin
		entry := 0;
		maxEntries := maxEntries / SizeOf( maxEntries );
		while ( ( not found ) and ( entry < maxEntries ) ) do begin
			if ( IsWin64 ) then
				hProcess := OpenProcess( PROCESS_QUERY_LIMITED_INFORMATION, False, processes[entry] )
			else
				hProcess := OpenProcess( PROCESS_QUERY_INFORMATION, False, processes[entry] );
			if ( hProcess <> 0 ) then begin
				lpFilename := '';
				SetLength( lpFilename, MAX_LENGTH );
				if ( GetProcessImageFileName( hProcess, lpFilename, MAX_LENGTH ) > 0 ) then begin
					length := Pos( #0, lpFilename ) - 1;
					filename := GetFilenameFromDevicename( Copy( lpFilename, 1, length ) );
					if ( LowerCase( ExtractFileName( filename ) ) = LowerCase( procName ) ) then begin
						found := True;
						Result := filename;
					end;
				end;
				CloseHandle( hProcess );
			end;
			entry := entry + 1;
		end;
	end;
end;

var
	MirandaIMPath : String;
	MirandaIMFolder : String;

function GetMirandaIMFolder(Param: String) : String;
begin
	Result := MirandaIMFolder + Param;
end;

// Close Miranda IM process
procedure CloseMirandaIM;
var
	wndMiranda : HWND;
begin
	wndMiranda := FindWindowByClassName( 'Miranda' );
	if ( wndMiranda <> 0 ) then begin	
		// Close application
		SendNotifyMessage( wndMiranda, WM_DESTROY, 0, 0 );
		Sleep( 2000 );
	end;
end;

// Check if Miranda IM is running and save its full path (returns True if still runing)
function DetectRunningMirandaIM(var MirandaPath : String): Boolean;
var
	Path : String;
begin
	Result := False;
	Path := 'foo';
	while ( Path <> '' ) do begin
		Path := GetRunning( 'miranda32.exe' );
		if ( Path = '' ) then
			Path := GetRunning( 'miranda64.exe' );
		if ( Path <> '' ) then begin
			MirandaPath := Path;
			if ( MsgBox( 'Miranda IM is running. Need to close it.', mbError, MB_RETRYCANCEL ) = IDCANCEL ) then begin
				Result := True;
				Path := '';
			end else
				CloseMirandaIM;
		end;
	end;
end;

function InitializeSetup(): Boolean;
var
	Path: String;
begin
	// Stop Windows Search
	StopService( 'WSearch' );

	// Detect Miranda IM installation folder
	Result := Not DetectRunningMirandaIM( Path );

	// From running Miranda IM
	if ( Path <> '' ) then begin
		MirandaIMPath := Path;
		MirandaIMFolder := AddBackslash( ExtractFileDir( Path ) );
	// From registry AppPath section
	end else if ( RegQueryStringValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\miranda64.exe', '', Path) and FileExists( Path ) ) then
		MirandaIMFolder := AddBackslash( ExtractFileDir( Path ) )
	else if ( RegQueryStringValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\miranda32.exe', '', Path) and FileExists( Path ) ) then
		MirandaIMFolder := AddBackslash( ExtractFileDir( Path ) )
	// From registry Uninstall section
	else if ( RegQueryStringValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Miranda IM', 'UninstallString', Path) and FileExists( Path ) ) then
		MirandaIMFolder := AddBackslash( ExtractFileDir( Path ) )
	else if ( RegQueryStringValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Miranda IM', 'UninstallString', Path) and FileExists( Path ) ) then
		MirandaIMFolder := AddBackslash( ExtractFileDir( Path ) )
	else
	// Use default path
		MirandaIMFolder := ExpandConstant( '{pf}\Miranda IM\' );
end;

procedure DeinitializeSetup();
var
	ResultCode : Integer;
begin
	// Restore previously closed Miranda IM
	if ( MirandaIMPath <> '' ) then
		if ( ( GetRunning( 'miranda32.exe' ) = '' ) and ( GetRunning( 'miranda64.exe' ) = '' ) ) then
			ExecAsOriginalUser( MirandaIMPath, '', '', SW_SHOW, ewNoWait, ResultCode );
end;

function InitializeUninstall(): Boolean;
var
	Foo : String;
begin
	// Stop Windows Search
	StopService( 'WSearch' );

	// Check if Miranda IM is running
	Result := Not DetectRunningMirandaIM( Foo );
end;
